/**
 * 简洁的 API 客户端 - 基于 fetch
 */

import type { ApiError } from './types';
import { useAuthStore } from '../stores/authStore';

/**
 * API 客户端类
 */
class ApiClient {
  private baseURL = '/api';
  private timeout = 30000;

  private async request<T>(url: string, options: RequestInit = {}): Promise<T> {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), this.timeout);

    // 获取认证token
    const { token } = useAuthStore.getState();

    try {
      const response = await fetch(`${this.baseURL}${url}`, {
        ...options,
        headers: {
          'Content-Type': 'application/json',
          ...(token && { Authorization: `Bearer ${token}` }),
          ...options.headers,
        },
        signal: controller.signal,
      });

      clearTimeout(timeoutId);

      let data: unknown;
      const contentType = response.headers.get('content-type');
      if (contentType?.includes('application/json')) {
        data = await response.json();
      } else {
        data = await response.text();
      }

      if (!response.ok) {
        // 处理401未授权错误 - 只在非登录页时重定向
        if (response.status === 401) {
          const { logout } = useAuthStore.getState();
          logout();
          // 检查当前是否在登录页，避免重复重定向
          if (!window.location.pathname.includes('/login')) {
            window.location.href = '/login';
          }
        }
        throw this.createError(response.status, data);
      }

      // 检查业务状态码 (200表示成功，201表示创建成功)
      if (data && typeof data === 'object' && 'code' in data) {
        const apiResponse = data as { code: number; data?: unknown; msg?: string; detail?: string };
        if (apiResponse.code !== 200 && apiResponse.code !== 201) {
          // 处理业务层面的401错误 - 只在非登录页时重定向
          if (apiResponse.code === 401) {
            const { logout } = useAuthStore.getState();
            logout();
            // 检查当前是否在登录页，避免重复重定向
            if (!window.location.pathname.includes('/login')) {
              window.location.href = '/login';
            }
          }
          throw this.createError(apiResponse.code, apiResponse);
        }
        // 如果有data字段，返回data字段；否则返回整个response对象（用于某些特殊API）
        return (apiResponse.data !== undefined ? apiResponse.data : apiResponse) as T;
      }

      return data as T;
    } catch (error) {
      clearTimeout(timeoutId);
      if (error instanceof Error && error.name === 'AbortError') {
        throw this.createError(0, '请求超时');
      }
      throw error;
    }
  }

  private createError(code: number, data: unknown): ApiError {
    // 🚨 优先使用后端返回的错误信息
    let backendMessage = '';
    let backendDetail = '';
    let backendRequestId = '';

    // 检查后端返回的错误信息 - 支持多种字段名
    if (typeof data === 'object' && data !== null) {
      const errorData = data as {
        msg?: string;
        message?: string;
        error?: string;
        detail?: string;
        request_id?: string;
      };

      // 优先级: msg > message > error
      backendMessage = errorData.msg || errorData.message || errorData.error || '';
      backendDetail = errorData.detail || '';
      backendRequestId = errorData.request_id || '';

      // 如果后端提供了明确的错误信息，直接使用
      if (backendMessage.trim()) {
        return {
          code,
          msg: backendMessage.trim(),
          detail: backendDetail,
          request_id: backendRequestId,
          timestamp: new Date().toISOString(),
          suggestions: this.getErrorSuggestions(code),
        };
      }
    }

    // 🔄 fallback: 使用默认错误消息映射
    const messages: Record<number, string> = {
      0: '网络连接失败，请检查网络连接',
      400: '请求参数错误，请检查输入数据',
      401: '身份验证失败，请重新登录',
      403: '权限不足，无法访问此资源',
      404: '请求的资源不存在',
      408: '请求超时，请稍后重试',
      422: '数据验证失败，请检查输入格式',
      429: '请求过于频繁，请稍后再试',
      500: '服务器内部错误，请联系管理员',
      502: '网关错误，服务暂时不可用',
      503: '服务暂时不可用，请稍后重试',
      504: '网关超时，请稍后重试',
    };

    const baseMessage = messages[code] || '请求失败';
    let detail = '';

    // 提取更多错误详情
    if (typeof data === 'string' && data.trim()) {
      detail = data;
    } else if (typeof data === 'object' && data !== null) {
      try {
        const errorObj = JSON.stringify(data);
        if (errorObj !== '{}') {
          detail = errorObj;
        }
      } catch {
        // JSON.stringify failed, ignore
      }
    }

    return {
      code,
      msg: baseMessage,
      detail: detail || `HTTP ${code} 错误`,
      timestamp: new Date().toISOString(),
      suggestions: this.getErrorSuggestions(code),
    };
  }

  // 根据错误代码提供处理建议
  private getErrorSuggestions(code: number): string[] {
    const suggestionMap: Record<number, string[]> = {
      0: ['检查网络连接', '确认服务器地址正确', '检查防火墙设置'],
      400: ['检查输入参数格式', '确认必填字段已填写', '查看API文档'],
      401: ['重新登录获取有效凭据', '检查Token是否过期', '联系管理员获取权限'],
      403: ['联系管理员申请权限', '确认账户状态正常', '检查访问范围'],
      404: ['确认请求路径正确', '检查资源是否存在', '核对API版本'],
      408: ['检查网络连接稳定性', '增加请求超时时间', '稍后重试'],
      422: ['检查数据格式', '确认字段类型正确', '查看验证规则'],
      429: ['降低请求频率', '稍后重试', '考虑使用缓存'],
      500: ['稍后重试', '联系技术支持', '检查服务器日志'],
      502: ['稍后重试', '检查服务器状态', '联系管理员'],
      503: ['稍后重试', '检查服务器负载', '等待服务恢复'],
      504: ['稍后重试', '检查网络延迟', '增加超时时间'],
    };

    return suggestionMap[code] || ['稍后重试', '联系技术支持'];
  }

  async get<T>(url: string, params?: Record<string, unknown>): Promise<T> {
    const searchParams = new URLSearchParams();
    if (params) {
      Object.entries(params).forEach(([key, value]) => {
        if (value !== undefined && value !== null) {
          searchParams.append(key, String(value));
        }
      });
    }
    const queryString = searchParams.toString();
    const fullUrl = queryString ? `${url}?${queryString}` : url;

    return this.request<T>(fullUrl);
  }

  async post<T>(url: string, data?: unknown): Promise<T> {
    return this.request<T>(url, {
      method: 'POST',
      body: data ? JSON.stringify(data) : undefined,
    });
  }

  async put<T>(url: string, data?: unknown): Promise<T> {
    return this.request<T>(url, {
      method: 'PUT',
      body: data ? JSON.stringify(data) : undefined,
    });
  }

  async delete<T>(url: string): Promise<T> {
    return this.request<T>(url, { method: 'DELETE' });
  }
}

export const api = new ApiClient();
